/*
 * Eugen Stoian <stoian.e@gmail.com> 2010
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "Real.h"
#include <QTextStream>
#include <math.h>
#include <cfloat>

#define IEEE_NAN 0xfff8000000000000
#define IEEE_POSITIVE_INFINITY 0x7ff0000000000000
#define IEEE_NEGATIVE_INFINITY 0xfff0000000000000

Real& Real::epsilon(){
    static Real epsilon(DBL_EPSILON);
    return epsilon;
}

Real& Real::nan(){

    static Real n(0.0,Real::NotANumber);
    return n;
}

Real& Real::positiveInfinity(){
    static Real posinf(0.0,Real::PositiveInfinity);
    return posinf;
}

Real& Real::negativeInfinity(){
    static Real neginf(0.0,Real::NegativeInfinity);
    return neginf;
}

Real& Real::pi(){
    static Real r(3.14159265358979323846);
    return r;
}

Real& Real::e(){
    static Real r(2.71828182845904523536);
    return r;
}

Real& Real::gamma(){
    static Real r(0.57721566490153286060);
    return r;
}

Real& Real::phi(){
    static Real r(1.61803398874989484820);
    return r;
}

Real& Real::lambda(){
    static Real r(1.303577269034296);
    return r;
}

Real& Real::alpha(){
    static Real r(2.502907875095892822283);
    return r;
}

Real& Real::delta(){
    static Real r(4.669201609102990671853);
    return r;
}

Real::Real(double value, Real::Limits limit):_value(value),_limit(limit){
    if(!_limit){
        if((_value!=_value)||isinf(_value)){
            if(_value!=_value)
                _limit = Real::NotANumber;
            if(isinf(_value)<0)
                _limit = Real::NegativeInfinity;
            if(isinf(_value)>0)
                _limit = Real::PositiveInfinity;
        }
   }
   else{
       if(_limit == Real::PositiveInfinity){
           _value = 1.0/0.0;
       }
       else if(_limit == Real::NegativeInfinity){
           _value = -1.0/0.0;
       }
       else {
           _value = 0.0/0.0;
       }
   }
}

Real::Real(const Real& r):_value(r._value),_limit(r._limit){
}

Real::~Real(){
}

Real& Real::operator=(const Real& r) {
    if(this!=&r){
        _value = r._value;
        _limit = r._limit;
    }
    return *this;
}

Real& Real::operator=(double d) {
    this->_value = d;
    if((_value!=_value)||isinf(_value)){
        if(_value!=_value)
            _limit = Real::NotANumber;
        if(isinf(_value)<0)
            _limit = Real::NegativeInfinity;
        if(isinf(_value)>0)
            _limit = Real::PositiveInfinity;
    }
    return *this;
}

double operator-(const Real& l) {
    return -l._value;
}

double operator+(const Real& l, double r) {
    return l._value+r;
}

double operator-(const Real& l, double r) {
    return l._value-r;
}

double operator*(const Real& l, double r) {
    return l._value*r;
}

double operator/(const Real& l, double r) {
    return l._value/r;
}

bool Real::isNan() const {
    return _limit & 4;
}

bool Real::isPositiveInfinity() const{
    return _limit & 1;
}

bool Real::isNegativeInfinity() const{
    return _limit & 2;
}

bool Real::isInfinity() const{
    return _limit & 3;
}

bool Real::isFinite() const {
    return !_limit;
}

bool Real::isStrictPositive() const {
    return _value>0;
}

bool Real::isStrictNegative() const {
    return _value<0;
}

bool Real::isPositive() const {
    return isZero()||isStrictPositive();
}

bool Real::isNegative() const {
    return isZero()||isStrictNegative();
}

bool Real::isZero() const {
    return _value==0.0;
}

bool Real::isPositiveZero() const{
    return isZero()&&(sign()==1);
}

bool Real::isNegativeZero() const{
    return isZero()&&(sign()==-1);
}

bool Real::isInvertible() const {
    return !(isNan()||isZero());
}

bool Real::isFalse() const {
    return isZero()||isNan();
}

bool Real::isTrue() const {
    return !isFalse();
}

int Real::sign() const {
    if(!signbit(_value))
        return 1;
    return -1;
}

QString Real::toString() const {
    QString ret;
    QTextStream str(&ret);
    str << _value;
    return ret;
}

Real r_sin(const Real& r){
    return sin(r);
}

Real r_cos(const Real& r){
    return cos(r);
}

Real r_tan(const Real& r){
    return tan(r);
}

Real r_sinh(const Real& r){
    return sinh(r);
}

Real r_cosh(const Real& r){
    return cosh(r);
}

Real r_tanh(const Real& r){
    return tanh(r);
}

Real r_asin(const Real& r){
    return asin(r);
}

Real r_acos(const Real& r){
    return acos(r);
}

Real r_atan(const Real& r){
    return atan(r);
}

Real r_asinh(const Real& r){
    return asinh(r);
}

Real r_acosh(const Real& r){
    return acosh(r);
}

Real r_atanh(const Real& r){
    return atanh(r);
}

Real r_log(const Real& r){
    return log(r);
}

Real r_sqrt(const Real& r){
    return sqrt(r);
}
